#include "CalcEngine.h"

CalcEngine::CalcEngine()
{

    this->m_expr = "";
    this->m_result = "";
    m_num_stack = new CalcStack<double>;
    m_op_stack = new OperatorStack;
}

CalcEngine::~CalcEngine()
{
    delete m_num_stack;
    delete m_op_stack;
}

void CalcEngine::get_expr(const QString &expr)
{
    m_expr = expr;
    m_expr.append('=');//增加一个终结符
}

QString & CalcEngine::get_result()
{
    calculate();
    return m_result;
}

void CalcEngine::calculate()
{
    QChar curr;
    QString number;
    QChar top;
    double op2;

    while ((curr = get_expr(m_expr, number)) != -1)
    {
        // 数字，直接入栈
        if (curr == 0)
        {
            m_num_stack->push(number.toDouble());
            continue;
        }

        while (!m_op_stack->push(curr))
        {
            if (m_op_stack->isFull())
            {
                m_result = "Stack Overflow: expression too long.";
                return;
            }
            if (!m_op_stack->isValid(curr))
            {
                m_result = "Invalid Operator: ";
                m_result.append(m_op_stack->top());
                return;
            }
move_in:
            top = m_op_stack->pop();
            switch (top.unicode())
            {
                case u'×':
                    m_num_stack->push(m_num_stack->pop() * m_num_stack->pop());
                    break;
                case u'÷':
                    op2 = m_num_stack->pop();
                    if (op2 == 0.0)
                    {
                        m_result = "Zero Divisor: ";
                        m_result.append(QString::number(m_num_stack->pop(), 10, 5));
                        m_result.append(" ÷ 0.0");

                        return;
                    }
                    m_num_stack->push(m_num_stack->pop() / op2);
                    break;
                case '+':
                    m_num_stack->push(m_num_stack->pop() + m_num_stack->pop());
                    break;
                case '-':
                    op2 = m_num_stack->pop();
                    m_num_stack->push(m_num_stack->pop() - op2);
                    break;
                case '=':
                    goto move_in;
                    break;
            }
        }
    }
    m_result = QString::number(m_num_stack->pop(), 10, 5);
    return;
}

//已知的bug: 只能识别单字符符号，不能识别例如 sin 等多字符的函数作为操作符
QChar CalcEngine::get_expr(const QString & expr, QString & number)
{
    static int last = 0;//上次解析的结束位置，即本轮解析开始位置  static 有状态，能够记忆
    QChar c = 0;
    int len = expr.length();
    number = "";

    //跳过空白
    while (last < len && (c = expr.at(last)) == ' ')
        last++;

    if (!c.isDigit())
    {
        if (last == len)//情况1，遇到终结符，则解析结束, 须重置 last
        {
            last = 0;
            return -1;
        }
        if (c != '.')
        {
            last++;
            return c;//情况2，是非小数点的符号，直接返回
        }
    }

    number.append(c);
    last ++;

    while (last < len && (c = expr.at(last)).isDigit())
    {
        number.append(c);//获取整数部分
        last++;
    }

    if (c == '.')
    {
        number.append(c);
        last++;
    }
    else
    {
        return 0;
    }

    while (last < len && (c = expr.at(last)).isDigit())
    {
        number.append(c);//获取小数部分
        last++;
    }

    return 0;//情况4，是小数
}
